import type { UseFetchOptions } from "nuxt/app";

/**
 * 默认响应结果接口
 * @template T 响应数据类型
 */
interface DefaultResult<T = any> {
  /** 响应状态码 */
  status: number;
  /** 响应数据 */
  data: T;
  /** 响应消息 */
  msg: string;
  /** 请求是否成功 */
  success: boolean;
}

/**
 * URL类型定义
 */
type UrlType = string | Request | Ref<string | Request> | (() => string | Request);

/**
 * HTTP选项类型
 * @template T 响应数据类型
 */
type HttpOption<T> = UseFetchOptions<DefaultResult<T>>;

/**
 * 请求配置接口
 * @template T 响应数据类型
 */
interface RequestConfig<T = any> extends HttpOption<T> {
  /** 忽略拦截，不走拦截，拥有 responseData，且 code !== 0 的情况下，直接返回 responseData */
  ignoreCatch?: boolean;
  /** 是否需要刷新数据 */
  needRefresh?: boolean;
  /** 忽略全局错误提示，走拦截，但是任何情况下都不会提示错误信息 */
  ignoreGlobalErrorMessage?: boolean;
  /** 请求超时时间（毫秒） */
  timeout?: number;
  /** 重试次数 */
  retryCount?: number;
}

/**
 * 核心请求函数
 * @param url 请求地址
 * @param params 请求参数
 * @param options 请求配置选项
 * @returns 返回响应数据或完整响应对象
 */
const request = async <T>(
  url: UrlType,
  params: any = {},
  options: RequestConfig<T> = {}
): Promise<DefaultResult<T> | T> => {
  try {
    // 参数验证
    if (!url) {
      throw new Error("请求地址不能为空");
    }

    const headers = useRequestHeaders(); // 获取所有headers信息
    const method = ((options?.method || "GET") as string).toUpperCase();
    const runtimeConfig = useRuntimeConfig();
    
    const baseURL: string = runtimeConfig.public?.baseUrl as string;
    console.log(baseURL,'baseURL');

    // 验证baseURL
    if (!baseURL) {
      console.warn("baseURL未配置，将使用相对路径");
    }

    /**
     * 处理错误异常
     * @param msg 错误消息
     */
    const handleError = (msg = "服务异常") => {
      console.error(`[Request Error]: ${msg}`);
      // TODO: 可以在这里集成全局错误提示组件
      // Swal.fire(msg)
    };

    /**
     * 执行请求的核心逻辑
     * @param retryCount 当前重试次数
     */
    const executeRequest = async (retryCount = 0): Promise<DefaultResult<T> | T> => {
      const { data, error, refresh } = await useFetch(url, {
        baseURL,
        headers,
        server: true,
        timeout: options.timeout || 30000, // 默认30秒超时
        params: method === "GET" ? params : undefined,
        body: ["POST", "PUT", "PATCH"].includes(method) 
          ? JSON.stringify(params) 
          : undefined,
        ...options,
      });

      const responseData = data.value as DefaultResult<T>;
      const { 
        ignoreCatch, 
        ignoreGlobalErrorMessage, 
        needRefresh, 
        retryCount: maxRetries = 0 
      } = options;

      // 处理网络错误或响应为空的情况
      if (error.value || !responseData) {
        const errorMessage = error.value?.message || error.value || "服务响应失败，请稍后重试";
        
        // 如果还有重试次数，则进行重试
        if (retryCount < maxRetries) {
          console.warn(`请求失败，正在进行第${retryCount + 1}次重试...`);
          await new Promise(resolve => setTimeout(resolve, 1000 * (retryCount + 1))); // 递增延迟
          return executeRequest(retryCount + 1);
        }

        if (!ignoreGlobalErrorMessage) {
          handleError(typeof errorMessage === 'string' ? errorMessage : '网络请求失败');
        }
        return Promise.reject(errorMessage);
      }

      // 处理业务逻辑
      const { status, data: result, msg } = responseData;
      
      // 判断是否需要刷新数据
      if (needRefresh && typeof refresh === 'function') {
        refresh();
      }

      // 接口请求成功，直接返回结果
      if (status === 200 || status === 0 || !status) {
        return result;
      }

      // 处理业务错误
      if (!ignoreCatch) {
        if (!ignoreGlobalErrorMessage) {
          handleError(msg || "业务处理失败");
        }
        return Promise.reject(msg || "业务处理失败，请稍后重试");
      }

      return responseData;
    };

    return await executeRequest();
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : "未知错误";
    console.error(`[Request Exception]: ${errorMessage}`, error);
    
    if (!options.ignoreGlobalErrorMessage) {
      console.error(`请求异常: ${errorMessage}`);
    }
    
    return Promise.reject(errorMessage);
  }
};

/**
 * 默认请求工具集合
 * 提供常用的HTTP请求方法，支持类型安全和错误处理
 */
export const useDefaultRequest = {
  /**
   * GET 请求
   * @template T 响应数据类型
   * @param url 请求地址
   * @param params 查询参数（可选）
   * @param options 请求配置选项（可选）
   * @returns Promise<T> 返回响应数据
   */
  get: <T = any>(url: string, params?: Record<string, any>, options?: RequestConfig<T>) => {
    return request<T>(url, params || {}, { method: 'GET', ...options });
  },

  /**
   * POST 请求
   * @template T 响应数据类型
   * @param url 请求地址
   * @param data 请求体数据（可选）
   * @param options 请求配置选项（可选）
   * @returns Promise<T> 返回响应数据
   */
  post: <T = any>(url: string, data?: Record<string, any>, options?: RequestConfig<T>) => {
    return request<T>(url, data || {}, { method: 'POST', ...options });
  },

  /**
   * PUT 请求
   * @template T 响应数据类型
   * @param url 请求地址
   * @param data 请求体数据（可选）
   * @param options 请求配置选项（可选）
   * @returns Promise<T> 返回响应数据
   */
  put: <T = any>(url: string, data?: Record<string, any>, options?: RequestConfig<T>) => {
    return request<T>(url, data || {}, { method: 'PUT', ...options });
  },

  /**
   * DELETE 请求
   * @template T 响应数据类型
   * @param url 请求地址
   * @param params 查询参数（可选）
   * @param options 请求配置选项（可选）
   * @returns Promise<T> 返回响应数据
   */
  delete: <T = any>(url: string, params?: Record<string, any>, options?: RequestConfig<T>) => {
    return request<T>(url, params || {}, { method: 'DELETE', ...options });
  },

  /**
   * PATCH 请求
   * @template T 响应数据类型
   * @param url 请求地址
   * @param data 请求体数据（可选）
   * @param options 请求配置选项（可选）
   * @returns Promise<T> 返回响应数据
   */
  patch: <T = any>(url: string, data?: Record<string, any>, options?: RequestConfig<T>) => {
    return request<T>(url, data || {}, { method: 'PATCH', ...options });
  },
};

/**
 * 使用说明：
 * 
 * 1. 基本使用方式：
 * ```typescript
 * // 定义接口函数
 * export function findNews(data?: { pageNum?: number; pageSize?: number }) {
 *   return useDefaultRequest.post<NewsListResponse>("/news/find", { 
 *     pageNum: 1, 
 *     pageSize: 20, 
 *     ...data 
 *   });
 * }
 * 
 * // 在组件中使用
 * try {
 *   const res = await findNews({ pageNum: 1, pageSize: 10 });
 *   // res 直接是后端返回的 data 字段内容
 *   console.log(res.list);
 * } catch (error) {
 *   console.error('请求失败:', error);
 * }
 * ```
 * 
 * 2. 配置选项说明：
 * - ignoreCatch: true - 忽略拦截，直接返回完整响应数据
 * - ignoreGlobalErrorMessage: true - 忽略全局错误提示
 * - needRefresh: true - 请求完成后刷新数据
 * - timeout: 10000 - 设置请求超时时间（毫秒）
 * - retryCount: 3 - 设置重试次数
 * 
 * 3. 类型安全：
 * ```typescript
 * interface UserInfo {
 *   id: number;
 *   name: string;
 *   email: string;
 * }
 * 
 * const userInfo = await useDefaultRequest.get<UserInfo>('/user/info');
 * // userInfo 具有完整的类型提示
 * ```
 * 
 * 注意：使用时请务必包在 try/catch 中处理异常
 */